package indi.defoliation.unknownrpg.core.listener;


import java.util.List;

import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerExpChangeEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.plugin.java.JavaPlugin;

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ListenerOptions;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.GamePhase;

import indi.defoliation.unknownrpg.api.RPGItemManager;
import indi.defoliation.unknownrpg.api.rpgevent.Cancellable;
import indi.defoliation.unknownrpg.api.rpgevent.entity.EntityAttackEvent;
import indi.defoliation.unknownrpg.api.rpgevent.entity.EntityWalkEvent;
import indi.defoliation.unknownrpg.api.rpgevent.player.PlayerChangeExpEvent;
import indi.defoliation.unknownrpg.api.rpgevent.player.PlayerMoveCameraEvent;
import indi.defoliation.unknownrpg.api.rpgevent.player.PlayerPickupItemEvent;
import indi.defoliation.unknownrpg.api.rpgevent.player.PlayerWalkEvent;
import indi.defoliation.unknownrpg.core.attribute.DefaultAttribute;

public class UnknownRPGListener implements Listener{

	private ProtocolManager pm;
	private JavaPlugin plugin;
	
	private final int i=128*32;
	
	private final DefaultAttribute att = new DefaultAttribute();

	public UnknownRPGListener(JavaPlugin plugin) {
		pm = ProtocolLibrary.getProtocolManager();
		this.plugin=plugin;
		addListenerOfEntityWalking();
	}

	@EventHandler(priority = EventPriority.MONITOR,ignoreCancelled = true)
	public void onDamage(EntityDamageByEntityEvent event) {

		EntityAttackEvent rpgEvent = setCancel(
				new EntityAttackEvent(event.getEntity(),event.getDamager(),event.getDamage(),event.getFinalDamage())
				,event);
		RPGItemManager.callEvent(rpgEvent);

		if(rpgEvent.isCancelled())
			event.setCancelled(true);
		else
			event.setDamage(rpgEvent.getChangeDamage());
	}
	
	@EventHandler()
	public void onInteractEntity(PlayerInteractAtEntityEvent event) {
		
		
		
		
	}
	@EventHandler(priority = EventPriority.MONITOR,ignoreCancelled = true)
	public void onPlayerMove(PlayerMoveEvent event) {
		Player player = event.getPlayer();
		Location from = event.getFrom();
		Location to = event.getTo();
		
		boolean cancel;
		
		if(isMove(from,to)) {
			PlayerWalkEvent playerWalkEvent = setCancel(new PlayerWalkEvent(player,from,to),event);
			RPGItemManager.callEvent(playerWalkEvent);
			cancel = playerWalkEvent.isCancelled();
		}
		else {
			PlayerMoveCameraEvent moveCameraEvent = setCancel(new PlayerMoveCameraEvent(player,from,to),event);
			RPGItemManager.callEvent(moveCameraEvent);
			cancel = moveCameraEvent.isCancelled();
			//走路的时候改变镜头估计不会触发这个，希望做到走路时仍然触发这个能做到玩家走路时不能四处看的效果。
		}
		if(cancel)
			event.setCancelled(true);
	}
	private boolean isMove(Location from,Location to) {
		return to.getX() != from.getX() || to.getY() != from.getY() || to.getZ() != from.getZ();
	}
	@EventHandler(priority = EventPriority.MONITOR,ignoreCancelled = true)
	public void onPlayerPickUpExpBall(PlayerExpChangeEvent event) {
		PlayerChangeExpEvent rpgEvent = new PlayerChangeExpEvent(event.getPlayer(),event.getAmount());
		RPGItemManager.callEvent(rpgEvent);
		event.setAmount(rpgEvent.getExp());
	}
	private <T extends Cancellable> T setCancel(T t,org.bukkit.event.Cancellable cancel) {
		t.setCancelled(att, cancel.isCancelled());
		return t;
	}
	
	@EventHandler(priority = EventPriority.MONITOR,ignoreCancelled = true)
	public void onPlayerPickupItem(org.bukkit.event.player.PlayerPickupItemEvent event) {
		PlayerPickupItemEvent rpgEvent = setCancel(
				new PlayerPickupItemEvent(event.getPlayer(),event.getItem()),event);
		if(rpgEvent.isCancelled())
			event.setCancelled(true);
		
		//rpg事件中的改变应该能改变event的item的改变，地址应该是一样的。
			
	}
	
	private void addListenerOfEntityWalking() {

		pm.addPacketListener(new PacketAdapter(PacketAdapter.params().plugin(plugin)
				.serverSide()
				.listenerPriority(ListenerPriority.MONITOR)
				.gamePhase(GamePhase.PLAYING)
				.optionAsync()
				.options(ListenerOptions.SKIP_PLUGIN_VERIFIER)
				.types(PacketType.Play.Server.REL_ENTITY_MOVE_LOOK)){

			@Override
			public void onPacketSending(PacketEvent event) {
				PacketContainer packet = event.getPacket();
				
				if(event.getPacketType().equals(PacketType.Play.Server.REL_ENTITY_MOVE_LOOK)) {
					if(packet.getEntityModifier(event).getValues().isEmpty())
						return;
					
					Entity e = packet.getEntityModifier(event).getValues().get(0);
					
					List<Integer> list = packet.getIntegers().getValues();
					if(list.isEmpty()||list.size()<4)
						return;
					int x = list.get(1);
					int y = list.get(2);
					int z = list.get(3);
					
					double deltaX = (double)x/i;
					double deltaY = (double)y/i;
					double deltaZ = (double)z/i;
					
					double prevX = e.getLocation().getX()-deltaX;
					double prevY = e.getLocation().getY()-deltaY;
					double prevZ = e.getLocation().getZ()-deltaZ;
					
					RPGItemManager.callEvent(new EntityWalkEvent(e,new Location(e.getWorld(),prevX,prevY,prevZ)
							,e.getLocation()));
					// 此事件能计算出之前，怪物的位置，但是不能保证100%准确，有小于1格内的误差。
				}
				
				
				
			}
			@Override
			public void onPacketReceiving(PacketEvent event) {
				
			}
		});
		
		
		
	}


}
